package com.xx.bili.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.github.pagehelper.PageHelper;
import com.xx.bili.domain.BiLiAccount;
import com.xx.bili.domain.BiLiLike;
import com.xx.bili.domain.BiLiLikeRecord;
import com.xx.bili.domain.model.ReplyInfo;
import com.xx.bili.domain.vo.BatchLikeVO;
import com.xx.bili.domain.vo.ReplyInfoVO;
import com.xx.bili.domain.vo.batch.BiLiBatchLike;
import com.xx.bili.mapper.BiLiAccountMapper;
import com.xx.bili.mapper.BiLiLikeMapper;
import com.xx.bili.mapper.BiLiLikeMapper;
import com.xx.bili.mapper.BiLiLikeRecordMapper;
import com.xx.bili.service.IBiLiLIkeService;
import com.xx.common.tools.IpPools.RespIPs;
import com.xx.common.utils.DateUtils;
import com.xx.common.utils.SecurityUtils;
import com.xx.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.beans.Transient;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 哔哩账号Service业务层处理
 *
 * @author ruoyi
 * @date 2024-09-28
 */
@Service
public class BiLiLikeServiceImpl implements IBiLiLIkeService {

    @Value("${ipPool.url}")
    private String ipPoolUrl;

    @Value("${ipPool.key}")
    private String ipPoolKey;

    @Value("${ipPool.orderNum}")
    private String ipPoolOrderNum;

    @Resource
    private BiLiLikeMapper biLiLikeMapper;

    @Resource
    private BiLiLikeRecordMapper biLiLikeRecordMapper;

    @Resource
    private BiLiAccountMapper biLiAccountMapper;

    /**
     * 查询哔哩点赞
     *
     * @param id 哔哩点赞主键
     * @return 哔哩点赞
     */
    @Override
    public BiLiLike selectBiLiLikeById(String id) {
        return biLiLikeMapper.selectBiLiLikeById(id);
    }

    /**
     * 查询哔哩点赞列表
     *
     * @param biLiLike 哔哩点赞
     * @return 哔哩点赞
     */
    @Override
    public List<BiLiLike> selectBiLiLikeList(BiLiLike biLiLike) {
        biLiLike.setCreateBy(SecurityUtils.getUserId().toString());
        return biLiLikeMapper.selectBiLiLikeList(biLiLike);
    }

    /**
     * 新增哔哩点赞
     *
     * @param biLiLike 哔哩点赞
     * @return 结果
     */
    @Override
    public List<String> insertBiLiLike(BiLiLike biLiLike) {

        if(StringUtils.isEmpty(biLiLike.getId())){
            biLiLike.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            biLiLike.setCreateTime(DateUtils.getNowDate());
            biLiLike.setCreateBy(SecurityUtils.getUserId().toString());
            biLiLikeMapper.insertBiLiLike(biLiLike);
        }

        String url = "";
        if ("点赞".equals(biLiLike.getHandleType())) {
            url = "https://api.bilibili.com/x/v2/reply/action"; // 点赞
        } else if ("点踩".equals(biLiLike.getHandleType())) {
            url = "https://api.bilibili.com/x/v2/reply/hate"; // 点踩
        }

        PageHelper.clearPage();

        // 直接查询未点赞的用户，一步到位
        List<BiLiAccount> unlikedAccounts = biLiAccountMapper.selectUnlikedAccounts(biLiLike.getOid(), biLiLike.getRpid(), SecurityUtils.getUserId().toString(), biLiLike.getCount());

        // 打乱列表顺序，保证每个账号都有点赞的机会
        Collections.shuffle(unlikedAccounts);

        // 计算实际需要使用的账号数量
        int actualCount = Math.min(unlikedAccounts.size(), biLiLike.getCount());

        // 获取需要的账号子列表（避免修改原列表）
        List<BiLiAccount> newList = unlikedAccounts.subList(0, actualCount);

        int LikeSuccessCount = 0;

        // 获取ip
//        String ipProxy = getIpProxy();
//        String[] split = ipProxy.split(":");
//        String proxyHost = split[0];
//        String proxyPort = split[1];

        Random random = new Random();

        for (BiLiAccount biLiAccount : newList) {

            // 每次点赞，加入随机延迟，50-100毫秒
//            try {
//                int time = 50 + random.nextInt(101);
//                System.out.println("点赞序列，待机：" + time + "毫秒");
//                Thread.sleep(time);
//            } catch (Exception e) {
//                throw new RuntimeException("待机异常：" + e);
//            }

            HashMap<String, Object> paramMap = new HashMap<>();
            paramMap.put("oid", biLiLike.getOid());
            paramMap.put("rpid", biLiLike.getRpid());
            paramMap.put("type", "1");
            paramMap.put("action", "1");

            // 提取加密参数
            String cookie = biLiAccount.getCookie();
            Matcher matcher = Pattern.compile("bili_jct=([^;]+)").matcher(cookie);
            if (matcher.find()) {
                paramMap.put("csrf", matcher.group(1));
            } else {
                System.out.println("bili_jct not found");
            }
            paramMap.put("statistics", "{\"appId\":100,\"platform\":5}");
            // 设置请求头
            Map<String, String> headers = new HashMap<>();
            headers.put("Cookie", cookie);

            // 发送POST请求
            String result = HttpUtil.createPost(url).headerMap(headers, true)
//                    .setHttpProxy(proxyHost, Integer.parseInt(proxyPort)) // 设置ip代理
                    .form(paramMap).execute().body();
            JSONObject json = new JSONObject(result);
            int code = json.getInt("code");

            // 封装记录数据
            BiLiLikeRecord biLiLikeRecord = new BiLiLikeRecord();
            biLiLikeRecord.setOid(biLiLike.getOid());
            biLiLikeRecord.setRpid(biLiLike.getRpid());
            biLiLikeRecord.setAccountId(biLiAccount.getId());
            biLiLikeRecord.setLikeId(biLiLike.getId());

            if (code == 0) {
                biLiLikeRecord.setMessage(biLiLike.getHandleType() + "成功");
                // 更新用户点赞次数
                biLiAccount.setCount(biLiAccount.getCount() + 1);
                biLiAccount.setEndTime(DateUtils.getNowDate());
                biLiAccountMapper.updateBiLiAccount(biLiAccount);

                // 点赞成功
                LikeSuccessCount++;
            } else {
                // 如果包含 request was banned 则出发了风控条件
                if(json.getStr("message").contains("request was banned")){
                    throw new RuntimeException("点赞频繁，请过一段时间在来");
                }
                biLiLikeRecord.setMessage(biLiLike.getHandleType() + "失败，失败原因：" + json.getStr("message"));
            }
            // 保存点赞记录
            biLiLikeRecord.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            biLiLikeRecord.setCode(code);
            biLiLikeRecord.setHandleType(biLiLike.getHandleType());
            biLiLikeRecord.setCreateTime(DateUtils.getNowDate());
            biLiLikeRecordMapper.insertBiLiLikeRecord(biLiLikeRecord);
        }

        // 下单数量
        Integer count = biLiLike.getCount();

        if(count - LikeSuccessCount > 0){
            biLiLike.setCount(biLiLike.getCount() - LikeSuccessCount);
            insertBiLiLike(biLiLike);
        }

        return null;
    }

    /**
     * 修改哔哩点赞
     *
     * @param biLiLike 哔哩点赞
     * @return 结果
     */
    @Override
    public int updateBiLiLike(BiLiLike biLiLike) {
        return biLiLikeMapper.updateBiLiLike(biLiLike);
    }

    /**
     * 批量删除哔哩点赞
     *
     * @param ids 需要删除的哔哩点赞主键
     * @return 结果
     */
    @Override
    public int deleteBiLiLikeByIds(String[] ids) {

        for (String biliLikeId : ids) {
            // 先查询所有的
            BiLiLike biLiLike = biLiLikeMapper.selectBiLiLikeById(biliLikeId);
            biLiLikeMapper.deleteBiLiLikeById(biliLikeId);

            // 同时删除对应的点赞记录数据
            List<BiLiLike> biLiLikes = biLiLikeMapper.selectBiLiLikeList(biLiLike);
            if(biLiLikes.isEmpty()){
                biLiLikeRecordMapper.deleteByBiLiLikeOidAndRpid(biLiLike.getOid(), biLiLike.getRpid());
            }
        }
        return 1;
    }

    @Override
    public Map<String, Object> checkOidRpidLikeCount(BiLiLike biLiLike) {

        if (biLiLike.getOid() == null || biLiLike.getRpid() == null || biLiLike.getHandleType() == null) {
            throw new IllegalArgumentException("关键参数不能为空【oid】【rpid】【下单类型】");
        }
        return biLiLikeRecordMapper.checkLikeAccountList(biLiLike.getOid(), biLiLike.getRpid(), biLiLike.getHandleType());
    }

    @Override
    public void batchBiLiLike(BatchLikeVO batchLikeVO) {

        // 1. 参数校验
        if (batchLikeVO.getReplies() == null || batchLikeVO.getReplies().isEmpty()) {
            throw new RuntimeException("评论列表不能为空");
        }

        if(batchLikeVO.getQuantity() > 0){
            Integer totalQuantity = batchLikeVO.getQuantity();
            List<ReplyInfoVO> replies = batchLikeVO.getReplies();
            int replyCount = replies.size();
            // 计算基础值和浮动范围
            int baseValue = totalQuantity / replyCount;
            int floatRange = (int) Math.round(baseValue * 0.5); // 20%浮动范围
            // 分配数量
            int remaining = totalQuantity;
            Random random = new Random();
            for (int i = 0; i < replyCount; i++) {
                ReplyInfoVO reply = replies.get(i);
                if (i == replyCount - 1) {
                    // 最后一条取剩余数量
                    reply.setCount(remaining);
                } else {
                    // 计算当前条的可分配范围
                    int min = Math.max(1, baseValue - floatRange);
                    int max = Math.min(baseValue + floatRange, remaining);
                    // 随机分配数量（保证至少分配1）
                    int allocated = min + random.nextInt(max - min + 1);
                    allocated = Math.min(allocated, remaining - (replyCount - i - 1)); // 确保剩余足够分配
                    reply.setCount(allocated);
                    remaining -= allocated;
                }
            }
        }


        for (ReplyInfoVO reply : batchLikeVO.getReplies()) {
            BiLiLike biLiLike = new BiLiLike();
            biLiLike.setOid(reply.getOid());
            biLiLike.setRpid(reply.getRpid());
            biLiLike.setHandleType(batchLikeVO.getHandleType());
            biLiLike.setCount(reply.getCount());
            insertBiLiLike(biLiLike);
        }

    }

    @Override
    public List<ReplyInfo> getReplyByMainUrl(BiLiBatchLike biLiBatchLike) {

        // 获取用户列表
//        List<BiLiAccount> accountList = biLiAccountMapper.selectBiLiAccountList(null);

        JSONObject json = null;
//        boolean flag = false;
//        String result = "";

        // 遍历用户列表获取Cookie直到得到一个可用的
//        for (BiLiAccount biLiAccount : accountList) {
//            // 设置请求头
//            Map<String, String> headers = new HashMap<>();
//            headers.put("Cookie", biLiAccount.getCookie());
//            result = HttpUtil.createGet(url).headerMap(headers, true).execute().body();
//            json = new JSONObject(result);
//            int code = json.getInt("code");
//            if (code == 0) {
//                flag = true;
//                break;
//            }
//        }
//        if (!flag) {
//            throw new RuntimeException("没有可用的在线账号");
//        }


        json = new JSONObject(biLiBatchLike.getUrl());
        JSONObject data = json.getJSONObject("data");
        JSONArray replies = data.getJSONArray("replies");

        List<ReplyInfo> replyInfoList = new ArrayList<>();

        try {
            for (int i = 0; i < replies.size(); i++) {
                JSONObject reply = replies.getJSONObject(i);
                long rpid = reply.getLong("rpid");
                long oid = reply.getLong("oid");
                // 直接从 reply 对象获取数据，避免重复解析
                JSONObject member = reply.getJSONObject("member");
                String uname = member.getStr("uname");

                JSONObject content = reply.getJSONObject("content");
                String message = content.getStr("message");

                replyInfoList.add(new ReplyInfo(oid, rpid, uname, message));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        System.out.println(replyInfoList);
        return replyInfoList;
    }

    private String getIpProxy(){

        String sign = "num=" + 1
                + "&result_type=json" //返回格式
                + "&trade_no=" + ipPoolOrderNum // 订单号 包时 9.6-1w
                + "&key=" + ipPoolKey;
        sign = sign + "&sign=" + SecureUtil.md5(sign);

        // 调用接口获取动态ip
        String getIpURL = ipPoolUrl + sign;
        cn.hutool.http.HttpResponse responseIps = HttpUtil.createRequest(Method.POST, getIpURL).timeout(5000).execute();

        RespIPs respIPs = JSONUtil.toBean(responseIps.body(), RespIPs.class);
        if("400".equals(respIPs.getCode())){
            throw new RuntimeException(respIPs.getMsg());
        }
        String ip = respIPs.getData().getProxy_list().get(0);

        return ip;
    }

}
